/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.openatom.ubml.model.common.definition.commonmodel.entity;

import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.openatom.ubml.model.common.definition.cef.IGspCommonField;
import org.openatom.ubml.model.common.definition.cef.collection.GspAssociationKeyCollection;
import org.openatom.ubml.model.common.definition.cef.element.GspAssociation;
import org.openatom.ubml.model.common.definition.cef.entity.ClassInfo;
import org.openatom.ubml.model.common.definition.cef.entity.DataTypeAssemblyInfo;
import org.openatom.ubml.model.common.definition.cef.entity.GspCommonDataType;
import org.openatom.ubml.model.common.definition.cef.entity.MdRefInfo;
import org.openatom.ubml.model.common.definition.cef.util.DataValidator;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonElement;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonModel;
import org.openatom.ubml.model.common.definition.commonmodel.IGspCommonObject;
import org.openatom.ubml.model.common.definition.commonmodel.collection.GspElementCollection;
import org.openatom.ubml.model.common.definition.commonmodel.collection.GspObjectCollection;
import org.openatom.ubml.model.common.definition.commonmodel.collection.GspUniqueConstraintCollection;
import org.openatom.ubml.model.common.definition.commonmodel.entity.object.GspColumnGenerate;
import org.openatom.ubml.model.common.definition.commonmodel.entity.object.GspCommonObjectType;


/**
 * The Definition Of Common Object,It`s The Abstract Definition Of BeObject、VoObject.
 *
 * @ClassName: GspCommonModel
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public class GspCommonObject extends GspCommonDataType implements IGspCommonObject, Cloneable {
    // 私有变量
    // private boolean logicDelete;
    private GspCommonObjectType objectType = GspCommonObjectType.MainObject;
    private GspColumnGenerate columnGenerateId = new GspColumnGenerate();

    private GspUniqueConstraintCollection containConstraints = new GspUniqueConstraintCollection();
    private IGspCommonObject parentObject;
    // private GspHirarchyInfo hirarchyInfo = new GspHirarchyInfo();
    // private GspElementCollection containElements;
    private GspObjectCollection containChildObjects;
    private String orderbyCondition = "";
    private String filterCondition = "";
    private boolean isVirtual;
    private boolean isReadOnly;

    private java.util.HashMap<String, IGspCommonElement> dicElements;

    private GspAssociationKeyCollection keys;
    private String belongModelId = "";
    private java.util.HashMap<String, Object> extProperties;


    // 构造函数
    /**
     * 持久化构件
     */
    private List<MdRefInfo> privateRepositoryComps;
    /**
     * 关联数据库对象ID
     */
    private String refObjectName;

    /**
     * 根据DO创建CO的构造函数
     *
     * @param dataTable DO元数据实体 //public GspCommonObject(GspDataTable dataTable) //
     *                  : this() //{ // this.dataTable = dataTable; // Initialize();
     *                  //}
     */


    // 公有属性
    /**
     * 当前结点所属的模型
     */
    private IGspCommonModel privateBelongModel;
    private IGspCommonElement idElement;
    private java.util.HashMap<String, IGspCommonElement> allElementDic;
    /**
     * 状态字段Id
     */
    private String privateStateElementID;

    public GspCommonObject() {
        setContainElements(new GspElementCollection(this));
        setContainChildObjects(new GspObjectCollection(this));
        // containElements = new GspElementCollection(this);
        // containChildObjects = new GspObjectCollection(this);
        dicElements = new java.util.HashMap<String, IGspCommonElement>();
        containConstraints = new GspUniqueConstraintCollection();
        keys = new GspAssociationKeyCollection();

        // setLogicDelete(false);
        // setRecordDelData(false);
        setIsReadOnly(false);
        setIsVirtual(false);

    }

    /**
     * CO默认构造函数
     * <p>
     * 初始化内部基本的集合属性
     */
    public final GspAssociationKeyCollection getKeys() {
        if (keys == null) {
            keys = new GspAssociationKeyCollection();
        }
        return keys;
    }

    public final void setKeys(GspAssociationKeyCollection value) {
        keys = value;
    }

    @JsonProperty("RepositoryComps")
    public final List<MdRefInfo> getRepositoryComps() {
        if (privateRepositoryComps == null) {
            privateRepositoryComps = new ArrayList<MdRefInfo>();
        }
        return privateRepositoryComps;
    }

    // /**
    // 是否逻辑删除
    //
    // */
    // public boolean getLogicDelete() {
    // return logicDelete;
    // }
    //
    // public void setLogicDelete(boolean value) {
    // logicDelete=value;
    // }

    public final void setRepositoryComps(List<MdRefInfo> value) {
        privateRepositoryComps = value;
    }

    /**
     * 节点类型 =>ObjectType
     */
    public GspCommonObjectType getObjectType() {
        return objectType;
    }

    public void setObjectType(GspCommonObjectType value) {
        objectType = value;
    }

    public String getRefObjectName() {
        return refObjectName;
    }

    public void setRefObjectName(String value) {
        refObjectName = value;
    }

    /**
     * ID生成规则
     */
    public GspColumnGenerate getColumnGenerateID() {
        return columnGenerateId;
    }

    // private IObjectCollection IGspCommonObject.getContainChildObjects() =>
    // getContainChildObjects();

    /**
     * @param value
     */
    public void setColumnGenerateID(GspColumnGenerate value) {
        columnGenerateId = value;
    }

    /**
     * 字段集合
     */
    public GspElementCollection getContainElements() {
        return (GspElementCollection)super.getContainElements();
    }

    protected void setContainElements(GspElementCollection value) {
        super.setContainElements(value);
    }

    /**
     * 子对象集合
     */
    @Override
    public GspObjectCollection getContainChildObjects() {
        if (containChildObjects == null) {
            containChildObjects = new GspObjectCollection(this.parentObject);
        }
        return containChildObjects;
    }

    public void setContainChildObjects(GspObjectCollection value) {
        containChildObjects = value;
    }

    /**
     * 唯一性约束
     */
    public GspUniqueConstraintCollection getContainConstraints() {
        return containConstraints;
    }

    public void setContainConstraints(GspUniqueConstraintCollection value) {
        containConstraints = value;
    }

    /**
     * 排序条件
     */
    public String getOrderbyCondition() {
        return orderbyCondition;
    }

    @Override
    public void setOrderbyCondition(String value) {
        orderbyCondition = value;
    }

    /**
     * 过滤 条件
     */

    public String getFilterCondition() {
        return filterCondition;
    }

    public void setFilterCondition(String filterCondition) {
        this.filterCondition = filterCondition;
    }

    @Override
    public boolean getIsReadOnly() {
        return isReadOnly;
    }

    @Override
    public void setIsReadOnly(boolean value) {
        isReadOnly = value;
    }

    @Override
    public boolean getIsVirtual() {
        return isVirtual;
    }

    @Override
    public void setIsVirtual(boolean value) {
        isVirtual = value;
    }

    public boolean isReadOnly() {
        return isReadOnly;
    }

    public void setReadOnly(boolean isReadOnly) {
        this.isReadOnly = isReadOnly;
    }

    // /**
    // 是否虚拟
    //
    // */
    public boolean isVirtual() {
        return isVirtual;
    }

    public void setVirtual(boolean isVirtual) {
        this.isVirtual = isVirtual;
    }

    public IGspCommonObject getParentObject() {
        return parentObject;
    }

    public void setParentObject(IGspCommonObject parentObject) {
        this.parentObject = parentObject;
    }

    public IGspCommonModel getBelongModel() {
        return privateBelongModel;
    }

    public void setBelongModel(IGspCommonModel value) {
        privateBelongModel = value;
    }

    /**
     * 标示当前对象的ID字段
     */
    @Override
    public final IGspCommonElement getIDElement() {
        if (idElement == null) {
            idElement = getCommonObjIDElement();
        }
        return idElement;
    }

    public final String getStateElementID() {
        return privateStateElementID;
    }

    public final void setStateElementID(String value) {
        privateStateElementID = value;
    }

    /**
     * 运行时为了减少遍历Element次数，提供按照LabelId为Key组织的属性字典
     */
    public java.util.HashMap<String, IGspCommonElement> getAllElementDic() {
        if (allElementDic != null) {
            return allElementDic;
        }
        allElementDic = new HashMap<String, IGspCommonElement>();
        ArrayList<IGspCommonElement> list = getAllElementList(true);
        for (IGspCommonElement gspCommonElement : list) {
            allElementDic.put(gspCommonElement.getLabelID(), gspCommonElement);
        }
        return allElementDic;
    }

    public void setAllElementDic(java.util.HashMap<String, IGspCommonElement> value) {
        allElementDic = value;
    }

    /**
     * 扩展模型元数据ID
     */
    public final String getBelongModelID() {
        if ((belongModelId == null || belongModelId.isEmpty()) && getBelongModel() != null) {
            belongModelId = getBelongModel().getID();
        }
        return belongModelId;
    }

    public void setBelongModelID(String value) {
        belongModelId = value;
    }

    /**
     * 作为子节点时在父级实体类上的属性名
     */
    @Override
    public String getPropertyName() {
        return String.format("$1", getCode(), "s");
    }


    /**
     * 扩展成员,用于扩展方法暂存运行时临时数据
     */

    public java.util.HashMap<String, Object> getExtProperties() {
        return (extProperties != null) ? extProperties : (extProperties = new java.util.HashMap<String, Object>());
    }

    /**
     * 获取所有子节点
     *
     * @return
     */
    public final java.util.ArrayList<IGspCommonObject> GetAllChildObjects() {
        java.util.ArrayList<IGspCommonObject> childObjects = new java.util.ArrayList<IGspCommonObject>();
        getChildObjects(this, childObjects);
        return childObjects;
    }

    public final IGspCommonObject getChildObjectById(String objectId) {
        for (IGspCommonObject child : getContainChildObjects()) {
            if (objectId.equals(child.getID())) {
                return child;
            }
        }
        return null;
    }

    /**
     * 根据列名查找属性元数据
     *
     * @param labelId 列名
     * @return 如果对应的元数据不存在 ，返回null
     */
    public final IGspCommonElement getElementByLabelId(String labelId) {
        DataValidator.checkForEmptyString(labelId, "labelID");
        IGspCommonElement element = getAllElementDic().get(labelId);
        return element;
    }

    /**
     * 创建字段
     *
     * @return
     */
    protected GspCommonElement createElement() {
        return new GspCommonElement();
    }

    private void createDictionary() {
        // _dicElements = new Dictionary<string, Element>();
        java.util.HashMap<String, IGspCommonElement> tempDict = new java.util.HashMap<String, IGspCommonElement>();

        // 查找当前的元素是否包含
        for (int i = 0; i < getContainElements().size(); i++) {
            createDictionary(getContainElements().getItem(i), tempDict);
        }
        dicElements = tempDict;
        // 查找子元素
        for (int i = 0; i < containChildObjects.size(); i++) {
            ((GspCommonObject)((containChildObjects.get(i) instanceof GspCommonObject) ? containChildObjects.get(i) : null))
                    .createDictionary();
        }
    }

    private void createDictionary(IGspCommonElement element, java.util.HashMap<String, IGspCommonElement> dict) {
        try {
            dict.put(element.getID(), element);
        } catch (java.lang.Exception e) {
            if (dict.containsKey(element.getID())) {
                throw new RuntimeException(String.format("数据模型的对象%1$s上面存在多个id为%2$s的字段", this.getName(), element.getID()));
            }
            throw e;
        }
        // 元素是一个关系,查找关联的元素
        if (element.getHasAssociation()) {
            for (int i = 0; i < element.getChildAssociations().size(); i++) {
                GspAssociation ass = element.getChildAssociations().get(i);
                for (int j = 0; j < ass.getRefElementCollection().size(); j++) {
                    IGspCommonElement ele = (IGspCommonElement)ass.getRefElementCollection().get(j);
                    boolean isContain = dict.containsKey(ele.getID());
                    // 不同的元素关联的相同的元素只添加一次
                    if (!isContain) {
                        createDictionary(ele, dict);
                    }
                }
            }
        }
    }

    /**
     * 获取标识当前对象的ID字段元素
     *
     * @return
     */
    private IGspCommonElement getCommonObjIDElement() {

        if (columnGenerateId != null) {
            IGspCommonField tempVar = findElement(columnGenerateId.getElementID());
            return (IGspCommonElement)((tempVar instanceof IGspCommonElement) ? tempVar : null);
        }
        return null;
    }

    private void getChildObjects(IGspCommonObject commonObject, java.util.ArrayList<IGspCommonObject> childObjects) {
        for (IGspCommonObject childObject : commonObject.getContainChildObjects()) {
            if (childObject.getContainChildObjects() != null) {
                getChildObjects(childObject, childObjects);
            }
            childObjects.add(childObject);
        }
    }

    /**
     * 是否包含非引用字段
     *
     * @param withChild 是否校验子节点中字段 返回结果为true时，包含非引用字段，则参与序列化；反之不参与序列化
     * @return
     */
    public final boolean hasNoneRefElement(boolean withChild) {
        if (getContainElements() != null && getContainElements().size() > 0) {
            for (IGspCommonField element : getContainElements()) {
                if (!element.getIsRef()) {
                    return true;
                }
                if (element.hasNoneRefElementInAssociation()) {
                    return true;
                }
            }
        }

        if (withChild && getContainChildObjects() != null && getContainChildObjects().size() > 0) {
            if (hasNoneRefElementInChild()) {
                return true;
            }
        }
        return false;
    }

    private boolean hasNoneRefElementInChild() {
        for (IGspCommonObject childObj : getContainChildObjects()) {
            if (childObj.hasNoneRefElement(true)) {
                return true;
            }
        }

        return false;
    }

    // 实现接口
    @Override
    public java.util.ArrayList<IGspCommonElement> getAllElementList(boolean containRef) {
        java.util.ArrayList<IGspCommonElement> elementList = new java.util.ArrayList<IGspCommonElement>();
        if (getContainElements() == null || getContainElements().size() == 0) {
            return elementList;
        }
        for (IGspCommonField item : getContainElements()) {
            IGspCommonElement element = (IGspCommonElement)item;
            elementList.add(element);
            if (!element.getHasAssociation() || !containRef) {
                continue;
            }
            for (GspAssociation association : element.getChildAssociations()) {
                for (IGspCommonField refElement : association.getRefElementCollection()) {
                    elementList.add((IGspCommonElement)refElement);
                }
            }
        }
        return elementList;
    }

    /**
     * 克隆
     *
     * @return
     */
    public GspCommonObject clone() {
        Object tempVar = null;
        try {
            tempVar = super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        GspCommonObject absObject = (GspCommonObject)((tempVar instanceof GspCommonObject) ? tempVar : null);
        if (absObject == null) {
            return null;
        }
        absObject.dicElements = new java.util.HashMap<String, IGspCommonElement>();
        // if (this.dataTable != null)
        // absObject.dataTable = this.dataTable.clone() as GspDataTable;
        if (columnGenerateId != null) {
            Object tempVar2 = columnGenerateId.clone();
            absObject.columnGenerateId = (GspColumnGenerate)((tempVar2 instanceof GspColumnGenerate) ? tempVar2 : null);
        }
        if (getContainElements() != null) {
            absObject.setContainElements(getContainElements().clone(absObject, null));
        }
        if (containConstraints != null) {
            absObject.containConstraints = containConstraints.clone(absObject);
        }
        if (containChildObjects != null) {
            absObject.setContainChildObjects(containChildObjects.clone(absObject));
        }
        // if (hirarchyInfo != null)
        // {
        // absObject.hirarchyInfo = hirarchyInfo.clone(absObject);
        // }
        return absObject;
    }

    /**
     * 克隆
     *
     * @param parentObj
     * @return
     */
    public final IGspCommonObject clone(IGspCommonObject parentObj) {
        Object tempVar = clone();
        GspCommonObject newObj = (GspCommonObject)((tempVar instanceof GspCommonObject) ? tempVar : null);
        if (newObj == null) {
            return null;
        }
        newObj.parentObject = parentObj;
        return newObj;
    }

    @Override
    public ClassInfo getGeneratedEntityClassInfo() {
        DataTypeAssemblyInfo assembly = getBelongModel().getEntityAssemblyInfo();
        String classNamespace = assembly.getDefaultNamespace();
        String className = String.format("I%1$s", super.getCode());
        return new ClassInfo(assembly, className, classNamespace);
    }

    @Override
    public IGspCommonElement findElement(String elementId) {
        if (elementId == null || elementId.isEmpty()) {
            return null;
        }
        // 如果字典不包含当前元素ID,遍历所有的节点,创建字典
        if (!dicElements.containsKey(elementId)) {
            createDictionary();
        } else {
            return dicElements.get(elementId);
        }

        return dicElements.getOrDefault(elementId, null);
    }
}